#include "nemu.h"
#include <stdlib.h>
#include <time.h>

CPU_state cpu;

const char *regsl[] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
const char *regsw[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
const char *regsb[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};

void reg_test() {
	srand(time(0));
	uint32_t sample[8];
	uint32_t eip_sample = rand();
	cpu.eip = eip_sample;

	int i;
	for(i = R_EAX; i <= R_EDI; i ++) {
		sample[i] = rand();
		reg_l(i) = sample[i];
		assert(reg_w(i) == (sample[i] & 0xffff));
	}

	assert(reg_b(R_AL) == (sample[R_EAX] & 0xff));
	assert(reg_b(R_AH) == ((sample[R_EAX] >> 8) & 0xff));
	assert(reg_b(R_BL) == (sample[R_EBX] & 0xff));
	assert(reg_b(R_BH) == ((sample[R_EBX] >> 8) & 0xff));
	assert(reg_b(R_CL) == (sample[R_ECX] & 0xff));
	assert(reg_b(R_CH) == ((sample[R_ECX] >> 8) & 0xff));
	assert(reg_b(R_DL) == (sample[R_EDX] & 0xff));
	assert(reg_b(R_DH) == ((sample[R_EDX] >> 8) & 0xff));

	assert(sample[R_EAX] == cpu.eax);
	assert(sample[R_ECX] == cpu.ecx);
	assert(sample[R_EDX] == cpu.edx);
	assert(sample[R_EBX] == cpu.ebx);
	assert(sample[R_ESP] == cpu.esp);
	assert(sample[R_EBP] == cpu.ebp);
	assert(sample[R_ESI] == cpu.esi);
	assert(sample[R_EDI] == cpu.edi);

	assert(eip_sample == cpu.eip);
}

void sreg_load(int sreg, uint16_t selector) {
    uint32_t index = selector >> 3;
    lnaddr_t desc_addr = cpu.gdtr.base + index * 8;//描述符地址

    uint32_t low = lnaddr_read(desc_addr, 4);
    uint32_t high = lnaddr_read(desc_addr + 4, 4);
    uint64_t desc = (uint64_t)low | ((uint64_t)high << 32);//整个描述符

    //提取base和limit 
    uint32_t base = ((desc >> 16) & 0xFFFF)
                  | (((desc >> 32) & 0xFF) << 16)
                  | (((desc >> 56) & 0xFF) << 24);

    uint32_t limit = (desc & 0xFFFF)
                   | (((desc >> 48) & 0x0F) << 16);

    //G位在描述符的第55位，G=1时精度为 4KB，需扩展 limit 
    uint8_t G = (desc >> 55) & 0x1;
    if (G) {
        limit = (limit << 12) | 0xFFF;
    }

    //写入对应段寄存器的 selector/base/limit（描述符cache）
    switch (sreg) {
        case R_CS:
            cpu.CS.selector = selector;
            cpu.CS.base = base;
            cpu.CS.limit = limit;
            break;
        case R_DS:
            cpu.DS.selector = selector;
            cpu.DS.base = base;
            cpu.DS.limit = limit;
            break;
        case R_SS:
            cpu.SS.selector = selector;
            cpu.SS.base = base;
            cpu.SS.limit = limit;
            break;
        case R_ES:
            cpu.ES.selector = selector;
            cpu.ES.base = base;
            cpu.ES.limit = limit;
            break;
        default:
            assert(0);
    }
}